package com.pactera.madp.cp.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pactera.madp.cp.api.entity.WorkContactEntity;
import com.pactera.madp.cp.api.entity.WorkEmployeeEntity;
import com.pactera.madp.cp.api.entity.WorkRoomEntity;
import com.pactera.madp.cp.api.entity.roomqc.ChildRuleEntity;
import com.pactera.madp.cp.api.entity.roomqc.QualityTestingRuleEntity;
import com.pactera.madp.cp.api.entity.roomqc.RuleTouchEntity;
import com.pactera.madp.cp.api.entity.wm.WorkMsgEntity;
import com.pactera.madp.cp.api.vo.msg.MsgVo;
import com.pactera.madp.cp.api.vo.roomqt.RoomRuleDetailVo;
import com.pactera.madp.cp.common.util.PageUtil;
import com.pactera.madp.cp.common.util.WxApiUtils;
import com.pactera.madp.cp.common.util.wm.WorkMsgHelper;
import com.pactera.madp.cp.handler.CorpContextHolder;
import com.pactera.madp.cp.mapper.roomqc.RuleTouchMapper;
import com.pactera.madp.cp.service.*;
import org.apache.commons.lang.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Service
public class RuleTouchServiceImpl extends ServiceImpl<RuleTouchMapper, RuleTouchEntity> implements RuleTouchService {

    @Autowired
    private IWorkContactService workContactService;
    @Autowired
    private IWorkMsgService workMsgService;
    @Autowired
    private IWorkRoomService workRoomService;
    @Autowired
    private QualityTestingRuleService qualityTestingRuleService;
    @Autowired
    private ChildRuleService childRuleService;
    @Autowired
    private IWorkEmployeeService workEmployeeService;
    @Autowired
    private ICorpService corpService;

    @Override
    public void checkRegularly(Integer corpId) {
        List<QualityTestingRuleEntity> list = qualityTestingRuleService.lambdaQuery()
                .eq(QualityTestingRuleEntity::getCorpId, corpId)
                .ne(QualityTestingRuleEntity::getDetectionType, 0)
                .list();
        if (list.size() == 0) return;
        list.forEach(f -> {
            String now = LocalTime.now().toString().substring(0, 8);
            if (f.getDetectionType() == 1 || (f.getStartTime().compareTo(now) < 0 && f.getEndTime().compareTo(now) > 0)) {
                List<ChildRuleEntity> childRuleEntities = childRuleService.lambdaQuery().eq(ChildRuleEntity::getFid, f.getId()).list();
                List<Integer> roomIds;
                if (f.getRoomIds() != null) {
                    List<String> idsStr = Arrays.asList(f.getRoomIds().split(","));
                    roomIds = idsStr.stream().map(m -> Integer.parseInt(m)).collect(Collectors.toList());
                } else {
                    return;
                }
                isTouch(roomIds, childRuleEntities, corpId);
            }
        });
    }

    @Override
    public IPage fQuery(Page page, Integer roomId, Integer type, Integer current, Integer size) {
        String wxid = workRoomService.getObj(Wrappers.<WorkRoomEntity>lambdaQuery().select(WorkRoomEntity::getWxChatId).eq(WorkRoomEntity::getId, roomId), o -> o.toString());

        Page page1 = PageUtil.split(workMsgService.page(wxid, type), current, size);
        ArrayList<MsgVo> vos = new ArrayList<>();
        List<WorkMsgEntity> records = page1.getRecords();
        records.forEach(f -> {
            MsgVo vo = new MsgVo();
            BeanUtils.copyProperties(f, vo);
            WorkContactEntity contact = workContactService.getOne(Wrappers.<WorkContactEntity>lambdaQuery()
                    .select(WorkContactEntity::getName, WorkContactEntity::getId)
                    .eq(WorkContactEntity::getWxExternalUserid, f.getFrom()));
            WorkEmployeeEntity employee = workEmployeeService.getOne(Wrappers.<WorkEmployeeEntity>lambdaQuery()
                    .select(WorkEmployeeEntity::getName,WorkEmployeeEntity::getWxUserId, WorkEmployeeEntity::getId)
                    .eq(WorkEmployeeEntity::getWxUserId, f.getFrom()));
            MsgVo.from from = new MsgVo.from();
            if (contact == null && employee.getWxUserId().equals(f.getFrom())) {
                from.setId(employee.getId());
                from.setName(employee.getName());
                vo.setIsCurrentUser(0);
            } else {
                from.setId(contact.getId());
                from.setName(contact.getName());
                vo.setIsCurrentUser(1);
            }
            vo.setFrom(from);
            vo.setContent(JSONUtil.parseObj(f.getContent()));
            vos.add(vo);
        });

        page1.setRecords(vos);
        return page1;
    }


    @Override
    public Boolean sendToEmployee(String latestTime, Integer ruleId, List<Integer> roomIdl, String ids, Integer corpId) {
        List<String> names = workRoomService.listObjs(Wrappers.<WorkRoomEntity>lambdaQuery().select(WorkRoomEntity::getName).in(WorkRoomEntity::getId, roomIdl), o -> o.toString());
        ChildRuleEntity rule = childRuleService.getById(ruleId);
        List<String> finalIds = Arrays.asList(ids.split(","));
        List<String> wxIds = workEmployeeService.listObjs(Wrappers.<WorkEmployeeEntity>lambdaQuery().select(WorkEmployeeEntity::getWxUserId)
                .in(WorkEmployeeEntity::getId, finalIds), o -> o.toString()
        );
        String type;
        if (rule.getTimeType() == 1) type = "小时";
        else if (rule.getTimeType() == 2) type = "分钟";
        else type = "天";
        String time = rule.getTime() + type;
        StringBuffer name = new StringBuffer();
        names.forEach(f -> {
            name.append("[" + f + "],");
        });
        name.deleteCharAt(name.length() - 1);

        String str = "触发时间: " + latestTime +
                "触发群聊: " + name +
                "触发规则: " + "群聊内超过" + time + "没有人回复客户消息";
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("msgtype", "text");
        JSONObject text = new JSONObject();
        text.put("content", str);
        jsonObject.put("text", text);
        String wxCorpId = corpService.getById(corpId).getWxCorpId();
        jsonObject.put("agentid", corpService.getWxSendMsgAgentIdByWxCorpId(wxCorpId));
        String join = StringUtils.join(wxIds, "|");
        jsonObject.put("touser", join);
        String s = jsonObject.toString();
        WxApiUtils.sendMsgToEmployeeByString(s, corpId, wxCorpId);
        return null;
    }

    RoomRuleDetailVo fQuery(Integer ruleId, Integer roomId) {
        QualityTestingRuleEntity one = qualityTestingRuleService.getOne(Wrappers.<QualityTestingRuleEntity>lambdaQuery()
                .eq(QualityTestingRuleEntity::getId, ruleId));


        List<Object> ids = childRuleService.listObjs(Wrappers.<ChildRuleEntity>lambdaQuery().select(ChildRuleEntity::getId).eq(ChildRuleEntity::getFid, ruleId));


        return disposeAll(roomId, ids);
    }

    private RoomRuleDetailVo disposeAll(Integer roomId, List<Object> ids) {
        List<RuleTouchEntity> ruleTouchs = this.lambdaQuery().in(RuleTouchEntity::getRuleId, ids).orderByDesc(RuleTouchEntity::getMsgId).list();

        WorkRoomEntity m = workRoomService.list(Wrappers.<WorkRoomEntity>lambdaQuery().eq(WorkRoomEntity::getId, roomId)).get(0);
        //装room信息
        RoomRuleDetailVo room = new RoomRuleDetailVo();
        room.setRoomId(m.getId());
        room.setRoomName(m.getName());
        //装统计数据
        AtomicReference<Long> max = new AtomicReference<>(0l);
        ids.forEach(f -> {
            // 得到最近的触发时间
            String msgTime = this.getObj(Wrappers.<RuleTouchEntity>lambdaQuery().select(RuleTouchEntity::getTime).eq(RuleTouchEntity::getRuleId, f).orderByDesc(RuleTouchEntity::getTime).last("limit 1"), o -> o.toString());
            Long aLong = Long.valueOf(msgTime);
            if (aLong > max.get()) max.set(aLong);
        });
        room.setLatestTime(DateTime.of(max.get()).toString());
        //统计群的周月数据
        getStatistic(room, ruleTouchs);

        return room;
    }

    private void getStatistic(RoomRuleDetailVo room, List<RuleTouchEntity> ruleTouchs) {
        AtomicReference<Integer> rTodayTime = new AtomicReference<>(0);
        AtomicReference<Integer> rWeekTime = new AtomicReference<>(0);
        AtomicReference<Integer> rMonthTime = new AtomicReference<>(0);
        AtomicReference<Integer> rTotalTime = new AtomicReference<>(0);
        AtomicReference<Integer> TodayTime = new AtomicReference<>(0);
        AtomicReference<Integer> WeekTime = new AtomicReference<>(0);
        AtomicReference<Integer> MonthTime = new AtomicReference<>(0);
        AtomicReference<Integer> TotalTime = new AtomicReference<>(0);

        List<Integer> ruleIds = ruleTouchs.stream().map(m -> m.getRuleId()).distinct().collect(Collectors.toList());
        Long weekBegin = DateUtil.beginOfWeek(new Date()).toTimestamp().getTime();
        LocalDateTime week = LocalDateTime.ofEpochSecond(weekBegin / 1000, 0, ZoneOffset.ofHours(8));
        Long monthBegin = DateUtil.beginOfMonth(new Date()).toTimestamp().getTime();
        LocalDateTime month = LocalDateTime.ofEpochSecond(monthBegin / 1000, 0, ZoneOffset.ofHours(8));
        Long todayBegin = DateUtil.beginOfMonth(new Date()).toTimestamp().getTime();
        LocalDateTime today = LocalDateTime.ofEpochSecond(todayBegin / 1000, 0, ZoneOffset.ofHours(8));
        List<RoomRuleDetailVo.detail> details = room.getDetails();
        ruleIds.forEach(f -> {
            RoomRuleDetailVo.detail detail = new RoomRuleDetailVo.detail();
            Long todayTime =  ruleTouchs.stream().filter(f1 -> f1.getRoomId().equals(room.getRoomId())).filter(f1 -> f1.getCreateTime().isAfter(today)).filter(f1 -> f1.getRuleId().equals(f)).count();
            Long weekTime =  ruleTouchs.stream().filter(f1 -> f1.getRoomId().equals(room.getRoomId())).filter(f1 -> f1.getCreateTime().isAfter(month)).filter(f1 -> f1.getRuleId().equals(f)).count();
            Long monthTime = ruleTouchs.stream().filter(f1 -> f1.getRoomId().equals(room.getRoomId())).filter(f1 -> f1.getCreateTime().isAfter(week)).filter(f1 -> f1.getRuleId().equals(f)).count();
            Long totalTime = ruleTouchs.stream().filter(f1 -> f1.getRoomId().equals(room.getRoomId())).filter(f1 -> f1.getRuleId().equals(f)).count();
            rTodayTime.set(rTodayTime.get() + todayTime.intValue());
            rWeekTime.set(rWeekTime.get() + weekTime.intValue());
            rMonthTime.set(rMonthTime.get() + monthTime.intValue());
            rTotalTime.set(rTotalTime.get() + totalTime.intValue());
            detail.setRuleId(f);
            detail.setTotalTime(totalTime.intValue());
            detail.setTodayTime(todayTime.intValue());
            detail.setWeekTime(weekTime.intValue());
            detail.setMonthTime(monthTime.intValue());
            details.add(detail);
        });
        details.forEach(f -> {
            TodayTime.set(f.getTodayTime() + TodayTime.get());
            WeekTime.set(f.getWeekTime() + WeekTime.get());
            MonthTime.set(f.getMonthTime() + MonthTime.get());
            TotalTime.set(f.getTotalTime() + TotalTime.get());
        });
        room.setTodayTime(TodayTime.get());
        room.setWeekTime(WeekTime.get());
        room.setMonthTime(MonthTime.get());
        room.setTotalTime(TotalTime.get());
    }

    private void isTouch(List<Integer> roomIds, List<ChildRuleEntity> rules, Integer corpId) {
        List<WorkRoomEntity> rooms = workRoomService.list(Wrappers.<WorkRoomEntity>lambdaQuery()
                .select(WorkRoomEntity::getWxChatId, WorkRoomEntity::getId)
                .in(WorkRoomEntity::getId, roomIds));
        List<String> contactWxIds = workContactService.listObjs(Wrappers.<WorkContactEntity>lambdaQuery()
                .select(WorkContactEntity::getWxExternalUserid)
                .eq(WorkContactEntity::getCorpId, corpId), o -> o.toString());
        rules.forEach(f -> {
            Integer time = f.getTime();
            Integer timeType = f.getTimeType();
            long compareUnix;
            long unixNow = System.currentTimeMillis();
            if (timeType == 1) {
                compareUnix = unixNow - time * 60 * 1000;
            } else if (timeType == 2){
                compareUnix = unixNow - time * 3600 * 1000;
            } else {
                compareUnix = unixNow - time * 3600 * 24 * 1000;
            }
            //查询所有最新记录与现在间隔超过规则时间
            ArrayList<Integer> tRoomIds = new ArrayList<>();
            for (WorkRoomEntity f1 : rooms) {
                List<WorkMsgEntity> list = workMsgService.isTouchqt(corpId, f1.getWxChatId(), compareUnix);
                if (list.size() == 0) {
                    continue;
                } else {
                    WorkMsgEntity workMsgEntity = list.get(0);
                    //如果客户的wxids包含消息的发送者，则算做一次触发
                    if (!contactWxIds.contains(workMsgEntity.getFrom())) continue;
                    if (isExist(workMsgEntity.getSeq(), f.getId())) continue;
                    //算做一次触发
                    tRoomIds.add(f1.getId());
                    RuleTouchEntity entity = new RuleTouchEntity(f.getId(), f1.getId(), workMsgEntity.getMsgTime(), workMsgEntity.getSeq());
                    this.save(entity);
                }
            }
            if (tRoomIds.size() != 0) sendToEmployee(DateTime.now().toString(), f.getId(), tRoomIds, f.getSendWho(), corpId);

        });
    }

    private boolean isExist(Long msgId, Integer ruleId) {
        Integer count = this.lambdaQuery().eq(RuleTouchEntity::getRuleId, ruleId).eq(RuleTouchEntity::getMsgId, msgId).count();
        if (count > 0) return true;
        return false;
    }


}
